package com.luo.comm.vo;

import com.alibaba.fastjson2.JSONObject;
import com.luo.comm.utils.MyArrayListUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * ReqBody 是根据reqBody的内容转存的对象，将其中特殊的字段进行处理，其他字段转为标准对象的临时实体类，主要供mpUtils处理。
 * 示例：{"select":"id,userName,status,updatedAt","size":5,"page":1,"between":[{"id":[3,3]}],"orderBy":[{"id":"asc"}]}
 *
 * */

@Data  // 省略了 setter\getter，但并不注入容器！
@Component  // 注入Spring容器，便于其他地方获取以检查是否合法bean
@NoArgsConstructor
public class ReqBody<T> {
    /** 要处理的目标实体类，new User()。 */
    private  T entity;

    /** 分页大小，即每一页多少条记录，也是当前要返回的记录数，用来计算limit，offset。 */
    private Integer size;

    /** 当前页，用来计算limit，offset。 */
    private Integer page;

    /** 排序LinkedList，支持多个排序对象，格式[{"id","desc"},{"createdAt","asc"}]*/
    private LinkedList orderBy;

    /** between字段，存的是多个between字段的列表集合，格式[{"createdAt":[1,2},{"updatedAt":[1,2}]*/
    private LinkedList<Object> between;

    /** select 是要查询的字段名称逗号分隔('id,name,age') */
    private String select;


    /** 生成一个新的ReqBody对象。
     * @param entity 是要处理的目标实体类
     * @param jsonObject 是Request的body原生JSONObject
     * */
    public ReqBody(T entity, JSONObject jsonObject){
        T newObj = entity;

        // 将特殊字段处理下，其余的当做实体类的字段，无效字段会自动过滤
        String Size = "size";
        if(jsonObject.containsKey(Size)){
            this.size =  jsonObject.getInteger(Size);
            jsonObject.remove(Size);
        }else{
            this.size =10;
        }

        String Page = "page";
        if(jsonObject.containsKey(Page)){
            this.page =  jsonObject.getInteger(Page);

            jsonObject.remove(Page);
        }else{
            this.page =1;
        }

        String OrderBy = "orderBy";
        this.orderBy =new LinkedList<>();
        if(jsonObject.containsKey(OrderBy)){
           if(jsonObject.get(OrderBy).getClass() == ArrayList.class){
               this.orderBy =MyArrayListUtil.getInstance((ArrayList)jsonObject.get(OrderBy));;
            }else{
               throw BusinessException.error("orderBy格式错误。应该是 [{'id':'asc'}]  这样的格式(单引号换成双引号)");
           }
            jsonObject.remove(OrderBy);
        }else{
            LinkedHashMap orderByFieldsMap =new LinkedHashMap();
            orderByFieldsMap.put("id","asc");
            this.orderBy.add(orderByFieldsMap);
        }


        // 由于between字段接收的是一个范围，但数据库存的是一个具体的值，所以需要转换，先存到列表，在mpUtils中进行转换成查询条件
        String Between = "between";
        this.between =new LinkedList<>();
        if(jsonObject.containsKey(Between)){
            if(jsonObject.get(Between).getClass() == ArrayList.class){
                this.between =MyArrayListUtil.getInstance((ArrayList)jsonObject.get(Between));;
            }else{
                throw BusinessException.error("between格式错误。应该是 [{'createdAt':['2023-07-01','2023-07-30']]  这样的格式(单引号换成双引号)");
            }
            jsonObject.remove(Between);
        }


        // select 字段处理
        String Select = "select";
        if(jsonObject.containsKey(Select)){
            this.select =jsonObject.getString(Select);
        }else{
            this.select = "*";
        }

        // 除了上述特殊字段以外的其他字段，都转为entity 。只会转换名称相一致的属性，类型不一致会报错
        try{
            newObj =(T) jsonObject.toJavaObject(entity.getClass());
            BeanUtils.copyProperties(newObj,entity);
        }catch (Exception ex){
            throw  BusinessException.error("转换为实体类的字段时出错了:"+ ex.getMessage());
        }

        this.entity =entity;

    }


}
